package com.ugoodtech.mdcc.client.service.impl;

import com.google.common.collect.Lists;
import com.mysema.query.BooleanBuilder;
import com.ugoodtech.mdcc.client.Utils.JudgementUtils;
import com.ugoodtech.mdcc.client.Utils.PageInfoWrapper;
import com.ugoodtech.mdcc.client.common.BizConstants;
import com.ugoodtech.mdcc.client.dto.PerformancePlanData.TypeData;
import com.ugoodtech.mdcc.client.dto.PerformancePlanVO;
import com.ugoodtech.mdcc.client.exception.BizException;
import com.ugoodtech.mdcc.client.exception.EnumBizError;
import com.ugoodtech.mdcc.core.domain.PerformanceReport;
import com.ugoodtech.mdcc.core.domain.PerformanceReportDetail;
import com.ugoodtech.mdcc.core.domain.QPerformanceReport;
import com.ugoodtech.mdcc.core.domain.QPerformanceReportDetail;
import com.ugoodtech.mdcc.core.repository.PerformanceReportDetailRepository;
import com.ugoodtech.mdcc.core.repository.PerformanceReportRepository;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.TextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class PerformancePlanRecordsFilter {

	public static ThreadLocal<PageInfoWrapper> pageInfoThreadLocal = new ThreadLocal<>();

	@Autowired
	private PerformanceReportRepository performanceReportRepository;

	@Autowired
	private PerformanceReportDetailRepository performanceReportDetailRepository;

	public static ThreadLocal<PageInfoWrapper> getPageInfoThreadLocal() {
		return pageInfoThreadLocal;
	}


	/**
	 * 找出某个用户或所有用户, 在某些年的数据, 并根据用户名分页，一页包含该用户所有年份的数据
	 */
	public List<PerformanceReportDetail> filterRecords(String employeeName, List<Integer> years,
			Integer specificYear,
			List<Integer> months, Integer pageIndex, Integer pageSize) {
		// 先进行分页筛选, 根据用户名来分页, 找出符合年份和某用户或所有用户的数据
//		PageHelper.startPage(pageIndex, pageSize);
		Pageable pageables=new PageRequest( pageIndex<=1?0:pageIndex-1, pageSize);
//		Page<PerformanceReport> byEmployeeNameAndYear = performanceReportRepository
//				.findByEmployeeNameAndYear(employeeName, specificYear, pageables);
		QPerformanceReport qPerformanceReport = QPerformanceReport.performanceReport;
		BooleanBuilder builder = new BooleanBuilder();
		if (employeeName != null) {
			builder.and(qPerformanceReport.employeeName.eq(employeeName));
		}
		if (specificYear != null) {
			builder.and(qPerformanceReport.year.eq(specificYear));
		}
		Page<PerformanceReport> byEmployeeNameAndYear = performanceReportRepository.findAll(builder, pageables);
		List<PerformanceReport> performanceReportDOListForPage = byEmployeeNameAndYear.getContent();
//		PageInfo<PerformanceReport> pageInfo = PageInfo.of(performanceReportDOListForPage);
		pageInfoThreadLocal.set(

				new PageInfoWrapper(byEmployeeNameAndYear.getNumber(), byEmployeeNameAndYear.getSize(), byEmployeeNameAndYear.getNumberOfElements(),
						byEmployeeNameAndYear.getTotalPages(), byEmployeeNameAndYear.getTotalElements(), null));
		if (CollectionUtils.isEmpty(performanceReportDOListForPage)) {
			return new ArrayList<>(0);
		}
		// 找出这些业绩报告有关用户的在当年和去年的数据
		List<PerformanceReport> performanceReportDOList = getDataOfThisAndLastYear(
				performanceReportDOListForPage, years);
		if (CollectionUtils.isEmpty(performanceReportDOList)) {
			return new ArrayList<>(0);
		}
		// Get username and filter data by username.
		return getPerformancePlanData(months, performanceReportDOList);
	}

	private List<PerformanceReportDetail> getPerformancePlanData(
			List<Integer> months, List<PerformanceReport> performanceReportDOList) {
		List<Long> planIds = new ArrayList<>(performanceReportDOList.size());
		performanceReportDOList
				.forEach(
						performanceReportDO -> planIds.add(performanceReportDO.getId()));
		return filterRecords(planIds, months);
	}

	/**
	 * 获取这些业绩报告有关用户的在某些年的计划数据
	 */
	private List<PerformanceReport> getDataOfThisAndLastYear(
			List<PerformanceReport> performanceReportDOListForPage,
			List<Integer> years) {
		// 如果要查的数据为空, 则直接返回, null表示不用查数据
		if (JudgementUtils.isNoQuery(performanceReportDOListForPage, years)) {
			return new ArrayList<>(0);
		}
		List<String> employeeName = new ArrayList<>();
		performanceReportDOListForPage
				.forEach(performanceReportDO -> employeeName.add(performanceReportDO.getEmployeeName()));
		return performanceReportRepository
				.findByEmployeeNameInAndYearIn(employeeName, years);
	}

	/**
	 * 根据用户名和年份筛选报告
	 */
	public List<PerformanceReport> getReport(String employeeName, Integer year) {
//		PerformanceReportExample example = new PerformanceReportExample();
//		PerformanceReportExample.Criteria criteria = example.or();
//		if (StringUtils.isNotEmpty(employeeName)) {
//			criteria.andEmployeeNameEqualTo(employeeName);
//		}
//		if (null != year) {
//			criteria.andYearEqualTo(year);
//		}
		BooleanBuilder builder = new BooleanBuilder();
		QPerformanceReport qPerformanceReport =QPerformanceReport.performanceReport;
		if (!TextUtils.isEmpty(employeeName)){
			builder.and(qPerformanceReport.employeeName.eq(employeeName));
		}
		if (year != null) {
			builder.and(qPerformanceReport.year.eq(year));
		}
		Iterable<PerformanceReport> all = performanceReportRepository.findAll(builder);
		return Lists.newArrayList(all);
	}

	/**
	 * 通过用户名，年份和操作类型筛选某一份特定的报告
	 */
	public PerformanceReport getSpecificReport(String employeeName, Integer year,
			Integer operationType) {
		if (employeeName == null || year == null || operationType == null) {
			return null;
		}
		return performanceReportRepository.findByEmployeeNameAndYearAndStatus(employeeName,year,operationType);
//		PerformanceReportExample example = new PerformanceReportExample();
//		PerformanceReportExample.Criteria criteria = example.or();
//		criteria.andEmployeeNameEqualTo(employeeName).andYearEqualTo(year)
//				.andStatusEqualTo(operationType);
//		List<PerformanceReport> performanceReportDOList =
//				performanceReportDOMapper.selectByExample(example);
//		if (CollectionUtils.isEmpty(performanceReportDOList)) {
//			return null;
//		} else {
//			return performanceReportDOList.get(0);
//		}
	}

	/**
	 * 获取某份报告的详情
	 */
	public List<PerformanceReportDetail> filterRecords(Long performanceReportId, Integer brandType,
			Integer clientType, Integer version, List<Integer> months) {
		BooleanBuilder builder = new BooleanBuilder();
		QPerformanceReportDetail qPerformanceReportDetail =QPerformanceReportDetail.performanceReportDetail;
		builder.and(qPerformanceReportDetail.performanceReport.id.eq(performanceReportId)).
				and(qPerformanceReportDetail.brandType.eq(brandType)).
				and(qPerformanceReportDetail.month.in(months)).
				and(qPerformanceReportDetail.customerType.eq(clientType)).
				and(qPerformanceReportDetail.version.eq(version));
		Iterable<PerformanceReportDetail> all = performanceReportDetailRepository.findAll(builder);
		return Lists.newArrayList(all);
//		PerformanceReportDetailExample example = new PerformanceReportDetailExample();
//		example.or().andPerformanceReportIdEqualTo(performanceReportId).andBrandTypeEqualTo(brandType)
//				.andMonthIn(months).andCustomerTypeEqualTo(clientType).andVersionEqualTo(version);
//		return performanceReportDetailDOMapperExt.selectByExample(example);
	}

	/**
	 * 获取某份报告的详情
	 */
	public List<PerformanceReportDetail> filterRecords(String employeeName, List<Integer> year,
			Integer operationType, Integer brandType,
			Integer clientType, Integer version, List<Integer> months) {
		BooleanBuilder builder = new BooleanBuilder();
		QPerformanceReportDetail qPerformanceReportDetail =QPerformanceReportDetail.performanceReportDetail;
		builder.and(qPerformanceReportDetail.employeeName.eq(employeeName)).
				and(qPerformanceReportDetail.year.in(year)).
				and(qPerformanceReportDetail.status.eq(operationType)).
				and(qPerformanceReportDetail.brandType.eq(brandType)).
				and(qPerformanceReportDetail.customerType.eq(clientType)).
				and(qPerformanceReportDetail.version.eq(version)).
				and(qPerformanceReportDetail.month.in(months));
		Iterable<PerformanceReportDetail> all = performanceReportDetailRepository.findAll(builder);
		return Lists.newArrayList(all);
//		PerformanceReportDetailExample example = new PerformanceReportDetailExample();
//		example.or().andEmployeeNameEqualTo(employeeName).andYearIn(year)
//				.andStatusEqualTo(operationType).andBrandTypeEqualTo(brandType)
//				.andMonthIn(months).andCustomerTypeEqualTo(clientType).andVersionEqualTo(version);
//		return performanceReportDetailDOMapperExt.selectByExample(example);
	}

	/**
	 * 获取某些报告各个版本在某些月份的数据
	 */
	public List<PerformanceReportDetail> filterRecords(List<Long> planIds, List<Integer> months) {
		if (JudgementUtils.isNoQuery(months, planIds)) {
			return new ArrayList<>(0);
		}
		BooleanBuilder builder = new BooleanBuilder();
		QPerformanceReportDetail qPerformanceReportDetail =QPerformanceReportDetail.performanceReportDetail;
		builder.and(qPerformanceReportDetail.performanceReport.id.in(planIds)).
				and(qPerformanceReportDetail.month.in(months));
		Iterable<PerformanceReportDetail> all = performanceReportDetailRepository.findAll(builder);
		return Lists.newArrayList(all);
//		PerformanceReportDetailExample example = new PerformanceReportDetailExample();
//		PerformanceReportDetailExample.Criteria criteria = example.or();
//		criteria.andPerformanceReportIdIn(planIds);
//		if (!Objects.isNull(months)) {
//			criteria.andMonthIn(months);
//		}
//		return performanceReportDetailDOMapperExt.selectByExample(example);
	}

	public List<PerformanceReportDetail> getReportOfSomeVersion(List<Integer> versions,
			Long reportId) {
		BooleanBuilder builder = new BooleanBuilder();
		QPerformanceReportDetail qPerformanceReportDetail =QPerformanceReportDetail.performanceReportDetail;
		builder.and(qPerformanceReportDetail.performanceReport.id.eq(reportId)).
		and(qPerformanceReportDetail.version.in(versions));
		Iterable<PerformanceReportDetail> all = performanceReportDetailRepository.findAll(builder);
		return Lists.newArrayList(all);
//		PerformanceReportDetailExample example = new PerformanceReportDetailExample();
//		example.or().andVersionIn(versions).andPerformanceReportIdEqualTo(reportId);
//		return performanceReportDetailDOMapperExt.selectByExample(example);
	}

	/**
	 * 根据用户名查找该用户业绩报告的年份信息
	 */
	public List<Integer> getYearGroup(String username) {
		if (StringUtils.isEmpty(username)) {
			throw new BizException(EnumBizError.PARAMS_INVALID.setErrMsg("请输入用户名"));
		}
		return performanceReportRepository.getYearGroup(username);
//		return performanceReportDetailDOMapperExt.getYearGroup(username);
	}

	public List<PerformancePlanVO> filterDataWhenGetYearPlan(List<PerformancePlanVO> planVOS) {
		planVOS.forEach(performancePlanVO -> {
			performancePlanVO.setData(performancePlanVO.getData().stream().filter(performancePlanData ->
					performancePlanData.getYear() != performancePlanVO.getYear() - 1
							|| (performancePlanData.getStatus() != BizConstants.PerformancePlan.OPERATION_TYPE_FORECAST
							&& performancePlanData.getStatus() != BizConstants.PerformancePlan.OPERATION_TYPE_PLAN)
			).collect(Collectors.toList()));
		});
		planVOS = planVOS.stream().filter(
				planVO -> CollectionUtils.isNotEmpty(planVO.getData()))
				.collect(Collectors.toList());
		return planVOS;
	}

	public List<PerformancePlanVO> filterDataWhenGetMonthPlan(List<PerformancePlanVO> planVOS) {
		planVOS.forEach(performancePlanVO -> {
			performancePlanVO.setData(performancePlanVO.getData().stream().filter(performancePlanData ->
					performancePlanData.getYear() != performancePlanVO.getYear() - 1
							&& performancePlanData.getStatus() == BizConstants.PerformancePlan.OPERATION_TYPE_PLAN
			).collect(Collectors.toList()));
		});
		return planVOS;
	}

	public List<PerformancePlanVO> filterDataWhenGetMonthPlanHistory(
			List<PerformancePlanVO> planVOS) {
		if (log.isDebugEnabled()) {
			log.debug("在获取月度历史记录数据时筛选出最新版本和计划的数据");
		}
		planVOS.forEach(performancePlanVO -> {
			// 筛选出各类数据中最大的版本号, 最后过滤掉不属于最大版本号的数据
			Map<TypeData, Integer> typeVersionMap = filterPlanDataVersion(performancePlanVO, true);
			performancePlanVO.setData(performancePlanVO.getData().stream().filter(performancePlanData ->
					typeVersionMap.get(new TypeData(performancePlanData.getBrandOrientation(),
							performancePlanData.getYear(), performancePlanData.getStatus(),
							performancePlanData.getProject()))
							.compareTo(performancePlanData.getVersion()) == 0
			).collect(Collectors.toList()));
		});
		return planVOS;
	}

	public List<PerformancePlanVO> filterLatestData(List<PerformancePlanVO> planVOS) {
		if (log.isDebugEnabled()) {
			log.debug("筛选出最新版本的数据");
		}
		planVOS.forEach(performancePlanVO -> {
			// 筛选出各类数据中最大的版本号, 最后过滤掉不属于最大版本号的数据
			Map<TypeData, Integer> typeVersionMap = filterPlanDataVersion(performancePlanVO, true);
			performancePlanVO.setData(performancePlanVO.getData().stream().filter(performancePlanData ->
					typeVersionMap.get(new TypeData(performancePlanData.getBrandOrientation(),
							performancePlanData.getYear(), performancePlanData.getStatus(),
							performancePlanData.getProject()))
							.compareTo(performancePlanData.getVersion()) == 0
			).collect(Collectors.toList()));
		});
		return planVOS;
	}

	public List<PerformancePlanVO> filterEarliestData(List<PerformancePlanVO> planVOS) {
		if (log.isDebugEnabled()) {
			log.debug("筛选出最早版本的数据");
		}
		planVOS.forEach(performancePlanVO -> {
			// 筛选出各类数据中最小的版本号, 最后过滤掉不属于最小版本号的数据
			Map<TypeData, Integer> typeVersionMap = filterPlanDataVersion(performancePlanVO, false);
			performancePlanVO.setData(performancePlanVO.getData().stream().filter(performancePlanData ->
					typeVersionMap.get(new TypeData(performancePlanData.getBrandOrientation(),
							performancePlanData.getYear(), performancePlanData.getStatus(),
							performancePlanData.getProject()))
							.compareTo(performancePlanData.getVersion()) == 0
			).collect(Collectors.toList()));
		});
		return planVOS;
	}

	public Map<TypeData, Integer> filterPlanDataVersion(PerformancePlanVO planVO, Boolean latest) {
		Map<TypeData, Integer> typeVersionMap = new HashMap<>(16);
		planVO.getData().forEach(performancePlanData -> {
			TypeData typeData = new TypeData(performancePlanData.getBrandOrientation(),
					performancePlanData.getYear(), performancePlanData.getStatus(),
					performancePlanData.getProject());
			int version = typeVersionMap.computeIfAbsent(typeData, k -> performancePlanData.getVersion());
			if (latest) {
				if (performancePlanData.getVersion() > version) {
					typeVersionMap.put(typeData, performancePlanData.getVersion());
				}
			} else {
				if (performancePlanData.getVersion() < version) {
					typeVersionMap.put(typeData, performancePlanData.getVersion());
				}
			}
		});
		return typeVersionMap;
	}

	public List<PerformancePlanVO> filterDataWhenGetDataNeedInput(List<PerformancePlanVO> planVOS, Integer year) {
		if (log.isDebugEnabled()) {
			log.debug("筛选出基本的如集采非集采的数据");
		}
		planVOS.forEach(performancePlanVO -> {
			performancePlanVO.setData(performancePlanVO.getData().stream().filter(performancePlanData -> (
					performancePlanData.getProject() == BizConstants.PerformancePlan.PROJECT_COLLECTION
							|| performancePlanData.getProject() == BizConstants.PerformancePlan.PROJECT_NOT_COLLECTION)
					&& Objects.equals(performancePlanData.getYear(), year)
			).collect(Collectors.toList()));
		});
		return planVOS;
	}

	public List<PerformancePlanVO> calculateHint(List<PerformancePlanVO> planVO) {
		countYearAmount(planVO);
		countBrandAmount(planVO);
		countStatusAmount(planVO);
		return planVO;
	}

	/**
	 * 将数据进行排序, 方便前端展示
	 */
	public List<PerformancePlanVO> sortData(List<PerformancePlanVO> planVOs) {
		planVOs.forEach(performancePlanVO -> sortData(performancePlanVO));
		return planVOs;
	}

	/**
	 * 将数据进行排序, 方便前端展示
	 */
	public PerformancePlanVO sortData(PerformancePlanVO planVO) {
		planVO.getData().sort((o1, o2) -> {
			int o1Hint = combineDataHint(o1.getBrandOrientation(), o1.getYear(), o1.getStatus(),
					o1.getProject());
			int o2Hint = combineDataHint(o2.getBrandOrientation(), o2.getYear(), o2.getStatus(),
					o2.getProject());
			if (o1Hint > o2Hint) {
				return 1;
			} else if (o1Hint == o2Hint) {
				return 0;
			} else {
				return -1;
			}
		});
		return planVO;
	}

	private Integer combineDataHint(Integer brand, Integer year) {
		return brand * 100 + year * 10;
	}

	private Integer combineDataHint(Integer brand, Integer year, Integer status) {
		return brand * 100 + year * 10 + status;
	}

	private Integer combineDataHint(Integer brand, Integer year, Integer status, Integer project) {
		return brand * 1000 + year * 100 + status * 10 + project;
	}


	/**
	 * 计算品牌需要合并单元格的数量
	 */
	private List<PerformancePlanVO> countBrandAmount(List<PerformancePlanVO> planVOs) {
		planVOs.forEach(performancePlanVO -> {
			if (performancePlanVO.getBrandAmount() == null) {
				performancePlanVO.setBrandAmount(new LinkedHashMap<>(2));
			}
			performancePlanVO.getData().forEach(performancePlanData -> {
				int amount = performancePlanVO.getBrandAmount()
						.computeIfAbsent(BizConstants.PerformancePlan.getBrand(performancePlanData.getBrandOrientation()),
								k -> 0);
				performancePlanVO.getBrandAmount()
						.put(BizConstants.PerformancePlan.getBrand(performancePlanData.getBrandOrientation()), ++amount);
			});
		});
		return planVOs;
	}

	/**
	 * 计算年份需要合并单元格的数量
	 */
	private List<PerformancePlanVO> countYearAmount(List<PerformancePlanVO> planVOs) {
		planVOs.forEach(performancePlanVO -> {
			Map<Integer, Integer> yearAmountMap = new LinkedHashMap<>(4);
			performancePlanVO.getData().forEach(performancePlanData -> {
				int amount = yearAmountMap.computeIfAbsent(
						combineDataHint(performancePlanData.getBrandOrientation(),
								performancePlanData.getYear()), k -> 0);
				yearAmountMap.put(combineDataHint(performancePlanData.getBrandOrientation(),
						performancePlanData.getYear()), ++amount);
			});
			performancePlanVO.setYearAmount(new ArrayList<>(yearAmountMap.values()));
		});
		return planVOs;
	}

	/**
	 * 计算状态需要合并单元格的数量
	 */
	private List<PerformancePlanVO> countStatusAmount(List<PerformancePlanVO> planVOs) {
		planVOs.forEach(performancePlanVO -> {
			Map<Integer, Integer> statusAmountMap = new LinkedHashMap<>(8);
			performancePlanVO.getData().forEach(performancePlanData -> {
				int amount = statusAmountMap.computeIfAbsent(
						combineDataHint(performancePlanData.getBrandOrientation(),
								performancePlanData.getYear(),
								performancePlanData.getStatus()), k -> 0);
				statusAmountMap.put(combineDataHint(performancePlanData.getBrandOrientation(),
						performancePlanData.getYear(),
						performancePlanData.getStatus()), ++amount);
			});
			performancePlanVO.setStatusAmount(new ArrayList<>(statusAmountMap.values()));
		});
		return planVOs;
	}

}
